package aqs;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * @author Jay
 */
public class MySemaphore {
    private Sync sync;

    public MySemaphore(int permits){
        this.sync = new Sync(permits);
    }

    public void acquire() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public void release(){
        sync.releaseShared(1);
    }

    /**
     * 非公平同步器
     */
    static class Sync extends AbstractQueuedSynchronizer{
        Sync(int permits){
            setState(permits);
        }

        final int getPermits(){
            return getState();
        }

        @Override
        protected boolean tryAcquire(int arg) {
            return tryAcquireShared(arg) >= 0;
        }

        @Override
        protected boolean tryRelease(int arg) {
            return tryReleaseShared(arg);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            return nonFairTryAcquireShared(arg);
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            return nonFairTryReleaseShared(arg);
        }

        final int nonFairTryAcquireShared(int acquires){
            while(true){
                int available = getState();
                int remaining = available - acquires;
                if(remaining < 0 || compareAndSetState(available, remaining)){
                    return remaining;
                }
            }
        }


        final boolean nonFairTryReleaseShared(int releases){
            while(true){
                int expect = getState();
                int update = expect + releases;
                if(update < expect || compareAndSetState(expect, update)){
                    return true;
                }
            }
        }
    }
}
